#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

#define BUFFERSIZE 5
int buf[BUFFERSIZE];		// 缓冲区
int in;			
int out;
sem_t mutex[2];		//mutex[0]:producer lock mutex[1]:consumer lock
sem_t empty;
sem_t full;

/* 打印缓冲区情况 */
void print()
{
	int i;
	printf("buffer: ");
	for(i = 0; i < BUFFERSIZE; i++)
   		printf("%d ", buf[i]);
   	printf("\tin:%d out:%d", in, out);
	printf("\n");
}

void* r1(){
	
	FILE*fp = fopen("data1.txt","r");
    while(1){
    	int t;
    	fscanf(fp,"%d", &t);//file io is slow, so do it outside the locker
        sem_wait(&empty);
        sem_wait(&mutex[0]);
        
	printf("r1:\t");
        buf[in]=t;
        print();
        in = (in + 1) % BUFFERSIZE;
        
        sem_post(&mutex[0]);
	sem_post(&full);	
        char c11 = fgetc(fp);
        if(c11=='\n' || c11==EOF) break;
    }
	return(NULL);
}

void* r2(){

	FILE*fp = fopen("data2.txt","r");
    while(1){
    	int t;
    	fscanf(fp,"%d", &t);//file io is slow, so do it outside the locker
        sem_wait(&empty);
        sem_wait(&mutex[0]);

	printf("r2:\t");
        buf[in]=t;
        print();
        in = (in + 1) % BUFFERSIZE;
        
        sem_post(&mutex[0]);
        sem_post(&full);
        char c11 = fgetc(fp);
        if(c11=='\n' || c11==EOF) break;
    }
	return(NULL);
}

void* w1(){
	int i=0;
	while(i<5)
    {	
    	int a,b;
    	
    	sem_wait(&full);
    	sem_wait(&mutex[1]);
    	a=buf[out];
    	out=(out+1)%BUFFERSIZE;
    	sem_post(&mutex[1]);
    	sem_post(&empty);
    	
    	sem_wait(&full);
    	sem_wait(&mutex[1]);
    	b=buf[out];
    	out=(out+1)%BUFFERSIZE;
    	sem_post(&mutex[1]);
    	sem_post(&empty);
    	
    	printf("Plus:\t%d+%d=%d\n",a,b,a+b);
    	//print();
	i++;
    }   
    return(NULL);
}

void* w2(){
	int i=0;
	while(i<5)
    {	
    	int a,b;
    	
    	sem_wait(&full);
    	sem_wait(&mutex[1]);
    	a=buf[out];
    	out=(out+1)%BUFFERSIZE;
    	sem_post(&mutex[1]);
    	sem_post(&empty);
    	
    	sem_wait(&full);
    	sem_wait(&mutex[1]);
    	b=buf[out];
    	out=(out+1)%BUFFERSIZE;
    	sem_post(&mutex[1]);
    	sem_post(&empty);
    	    	
    	printf("Multi:\t%d*%d=%d\n",a,b,a*b);
    	//print();
	i++;
    }   
    return(NULL);
}

int main(){
	pthread_t id1, id2, id3, id4;
	int ret1, ret2, ret3, ret4;

	in=0;
	out=0;
	sem_init(&mutex[0], 1, 1);
	sem_init(&mutex[1], 1, 1);
	sem_init(&full, 1, 0);			//is to be shared(1) or not(0), init_value
	sem_init(&empty, 1, BUFFERSIZE);
	
	for(int i=0;i<BUFFERSIZE;i++){
		buf[i]=0;
	}
	
	ret1 = pthread_create(&id1, NULL, (void *)r1, NULL);
	if(ret1){
		printf("ERROR:	failed to create thread r1!\n");
	}
	
	ret2 = pthread_create(&id2, NULL, (void *)r2, NULL);
	if(ret2){
		printf("ERROR:	failed to create thread r2!\n");
	}
	
	ret3 = pthread_create(&id3, NULL, (void *)w1, NULL);
	if(ret3){
		printf("ERROR:	failed to create thread w1!\n");
	}
	
	ret4 = pthread_create(&id4, NULL, (void *)w2, NULL);
	if(ret4){
		printf("ERROR:	failed to create thread w2!\n");
	}
	
	pthread_join(id1, NULL);
	pthread_join(id2, NULL);
	pthread_join(id3, NULL);
	pthread_join(id4, NULL);
	
	printf("All work's done.Quit.\n");
	
	return 0;
}
